#include "tls_rsa.h"

int pkcs1pad_sign(unsigned char *key, PACKET *in, int in_size, PACKET *out, int out_size) {
	struct crypto_akcipher *tfm;
    struct akcipher_request *req;
    struct scatterlist src, dst;
    struct crypto_wait wait;
	int ret;
	tfm = crypto_alloc_akcipher("pkcs1pad(rsa,sha512)", 0, 0);

    if (IS_ERR(tfm)) {
        ret = PTR_ERR(tfm);
        return -1;
    }
    ret = crypto_akcipher_set_priv_key(tfm, key + 26, 2350);
    // pr_info("private keylen: %d\n", *(short *)(key + 24));
	printk("crypto_sig_set_privkey ret:%d\n", ret);
	if (ret < 0) return -1;

    req = akcipher_request_alloc(tfm, GFP_KERNEL);
    if (!req) {
        ret = -ENOMEM;
        return -1;
    }

    sg_init_one(&src, in, 32);
    sg_init_one(&dst, out, 512);
    akcipher_request_set_crypt(req, &src, &dst, 32, 512);
    crypto_init_wait(&wait);
    akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
                                      CRYPTO_TFM_REQ_MAY_SLEEP,
                                      crypto_req_done, &wait);
    ret = crypto_wait_req(crypto_akcipher_sign(req), &wait);
	printk("crypto_akcipher_sign ret:%d\n", ret);
    print_hex_dump(KERN_CONT, "sig:", DUMP_PREFIX_OFFSET, 16, 1, out, 512, false);
    kfree(req);
    crypto_free_akcipher(tfm);
	return ret;
}

int pkcs1pad_verify(unsigned char *key, PACKET *in, int in_size, PACKET *out, int out_size) {
	int ret = 0;
	struct crypto_akcipher *tfm;
    struct akcipher_request *req;
    // struct scatterlist src, dst;
    struct scatterlist src_sg[2];
    struct crypto_wait wait;
	tfm = crypto_alloc_akcipher("pkcs1pad(rsa,sha512)", 0, 0);

    if (IS_ERR(tfm)) {
        ret = PTR_ERR(tfm);
        return -1;
    }
    ret = crypto_akcipher_set_pub_key(tfm, key, 526);
	printk("crypto_akcipher_set_pubkey ret:%d\n", ret);
	if (ret < 0) return -1;
	// ret = crypto_sig_verify(sig, out, 512, in, 32);
	// printk("crypto_sig_verify ret:%d\n", ret);
    req = akcipher_request_alloc(tfm, GFP_KERNEL);
    if (!req) {
        ret = -ENOMEM;
        return -1;
    }

    // sg_init_one(&src, in, 32);
    // sg_init_one(&dst, out, 512);
    sg_init_table(src_sg, 2);
    sg_set_buf(&src_sg[0], in, in_size);
    sg_set_buf(&src_sg[1], out, out_size);
    // akcipher_request_set_crypt(req, &src, &dst, 32, 512);
    akcipher_request_set_crypt(req, src_sg, NULL, in_size, out_size);
    crypto_init_wait(&wait);
    akcipher_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG |
                                      CRYPTO_TFM_REQ_MAY_SLEEP,
                                      crypto_req_done, &wait);
    ret = crypto_wait_req(crypto_akcipher_verify(req), &wait);
	printk("crypto_akcipher_verify ret:%d\n", ret);
    kfree(req);
    crypto_free_akcipher(tfm);
	return ret;
	return ret;
}
